#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#




import logging

import cgi
import wsgiref.handlers

import zipfile
from StringIO import StringIO

#import datetime

from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template


class Therapists(db.Model):
        tid=db.StringProperty() #id for therapist
        tGoogle=db.UserProperty() #connects to Google ID for therapist
        clients= db.ListProperty(db.Key) #list of keys to clients

class Clients(db.Model):
        cid=db.StringProperty()
        nowLoaded=db.ListProperty(db.Key) #list of keys of decks now on phone
        toLoad=db.ListProperty(db.Key) #list of keys of decks to load
        toUnload=db.ListProperty(db.Key) #list of keys of decks to unload
        stats=db.ListProperty(db.Key) #list of keys to stat reports
        
class StatReports(db.Model):
                deckName=db.StringProperty()
                numberRight=db.IntegerProperty()
                numberWrong=db.IntegerProperty()
                date=db.StringProperty()
                #date=db.DateProperty()
#code from deck builder..................................
class CardTemp(db.Model):
	cardName=db.StringProperty()
	cardImage=db.BlobProperty()
	hint1Text=db.StringProperty()
	hint2Text=db.StringProperty()
	hint3Text=db.StringProperty()
	hint1Audio=db.BlobProperty()
	hint2Audio=db.BlobProperty()
	hint3Audio=db.BlobProperty()
	hint1HasAudio=db.BooleanProperty()
	hint2HasAudio=db.BooleanProperty()
	hint3HasAudio=db.BooleanProperty()


class DeckTemp(db.Model):
	name=db.StringProperty()
	cards=db.ListProperty(db.Key) #keys for cards



zfile = StringIO() 
#end code from deckbuilder...........................................

class Decks(db.Model):
        name=db.StringProperty() 
        #descr=db.TextProperty() #description
        manifest=db.StringProperty() #a string that lists the cards in the deck

class LoginPage(webapp.RequestHandler):
 def get(self):
    user = users.get_current_user()
    if user:
      #greeting = ("Welcome, %s! (<a href=\"%s\">sign out</a>)" %(user.nickname(), users.create_logout_url("/")))
      self.redirect("/ther")
    else:
      greeting = ("<a href=\"%s\">Sign in or register</a>." %users.create_login_url("/"))
      self.response.out.write("<html><body>%s</body></html>" % greeting) 


class TherapistPage(webapp.RequestHandler):
  def get(self):
    #test code follows.......................................................
    #if Decks.all().count()==0: #if this hasn't already happened
    #        for i in range(5):
    #               deckName="Deck"+str(i)
    #               d=Decks()
    #               d.name=deckName
    #               d.put()
    #end test code ...............................................
    #check if current user is a therapist in the db
    user=users.get_current_user()
    q=Therapists.all().filter("tGoogle =",user)
    if q.count()==0:         #if no, create a new therapist that is them, and set t to that
            t=Therapists()
            t.tGoogle=user
            t.put()
    else: #if yes, set t to them and go ahead
            t=q[0]  #assume there is only 1 therapist w this id
          
    if len(t.clients)>0:
            self.response.out.write('<html><head><link type="text/css" rel="stylesheet" href="/stylesheets/main.css" /></head><body>')
            self.response.out.write('<img src="/images/banga.png">')
            self.response.out.write(("<p>Welcome, %s! (<a href=\"%s\">sign out</a>)" %(users.get_current_user().nickname(), users.create_logout_url("/"))))
            self.response.out.write('<form action="/ther" enctype="multipart/form-data" method="post">'
                            '<div><label>Clients:</label></div>'
                            '<SELECT NAME="client" SIZE="7">')
            #find the current therapist
            user=users.get_current_user()
            t=Therapists.all().filter("tGoogle =",user)[0]
                #really should handle the failure cases where there is no such therapist, or too many
            logging.info(t.tid)
            for ck in t.clients: #loop thru the client keys for this therapist
              thiscid=Clients.get(ck).cid #use the key to get the client's id
              logging.info(thiscid)
              self.response.out.write('<OPTION>'+thiscid)
            self.response.out.write('</SELECT><input type="submit" value="choose"></form>'
                            '<a href="addc">Add New Client</a>'
                            '</body></html>')
    else:
            self.response.out.write('<html><head><link type="text/css" rel="stylesheet" href="/stylesheets/main.css" /></head><body>')
            self.response.out.write('<img src="/images/banga.png">')
            self.response.out.write(("<p>Welcome, %s! (<a href=\"%s\">sign out</a>)" %(users.get_current_user().nickname(), users.create_logout_url("/"))))
            self.response.out.write('<p>No clients found.'
                            '<p><a href="addc">Add New Client</a>'
                            '</body></html>')
      

  def post(self):
        thiscid = self.request.get("client") #get the selected client id from the post message
        logging.info("selected: "+thiscid)
        #self.response.out.write("found client "+thiscid) #this will go to the client page 
        self.redirect('/client?'+thiscid) #append client id to the get

class AddClient(webapp.RequestHandler):
  def get(self):
          self.response.out.write('<html><head><link type="text/css" rel="stylesheet" href="/stylesheets/main.css" /></head><body>'
                            '<img src="/images/banga.png">'
                            '<form action="/addc" enctype="multipart/form-data" method="post">'
                            '<div><label>Enter new client ID:</label></div>'
                            '<input name="newID" type="text" value="new client ID">'
                            '<input type="submit" value="Enter"></form>'
                            '</body></html>')
  def post(self):
        thiscid = self.request.get("newID") #get the new client id from the post message
        logging.info("selected: "+thiscid)
        q=Clients.all().filter("cid =",thiscid)
        logging.info(q.count())
        if q.count()>0:
                self.response.out.write('<html><body>'
                            '<form action="/addc" enctype="multipart/form-data" method="post">'
                            '<div><label>That ID is taken. Choose a new ID:</label></div>'
                            '<input name="newID" type="text" value="new client ID">'
                            '<input type="submit" value="Enter"></form>'
                            '</body></html>')
        else:
                newC=Clients()
                newC.cid=thiscid
                newC.put()
                user=users.get_current_user()
                t=Therapists.all().filter("tGoogle =",user)[0]
                #really should handle the failure cases where there is no such therapist, or too many
    
                t.clients.append(newC.key())
                t.put()
        
                self.redirect('/ther')
class ClientPage(webapp.RequestHandler):
        def get(self):
                #get the client id from request
                clientID=self.request.query_string
                logging.info("client from get:"+clientID)
                c=Clients.all().filter("cid =",clientID)[0]
                #spit out basic starting html for page
                self.response.out.write('<html><head><link type="text/css" rel="stylesheet" href="/stylesheets/main.css" /></head><body>')
                self.response.out.write('<img src="/images/banga.png">')
                #stats
                if len(c.stats)==0:
                        self.response.out.write('<div style="color: blue; font-family: Arial; ">No performance records for this client.</div>')
                else:
                        self.response.out.write('<div><textarea rows="30" readonly="true">')
                        for rk in c.stats:
                                r=StatReports.get(rk)
                                #dateString=str(r.date.month)+"/"+str(r.date.day)+"/"+str(r.date.year)
                                dateString=r.date
                                rep="Deck: "+r.deckName+" Number right: "+str(r.numberRight)+" Number wrong: "+str(r.numberWrong)+" Date: "+dateString
                                self.response.out.write(rep+"\n")
                        self.response.out.write('</textarea></div>')
                #end stats
                self.response.out.write('<form action="/client?'+clientID+'" enctype="multipart/form-data" method="post">') #all buttons will submit this form
                #deck management
                self.response.out.write('<div style="padding-top:1cm">') 
                #first the list of decks available
                self.response.out.write('<div style="float:left"><div><label>Decks available:</label></div>'
                            '<SELECT NAME="availDeck" SIZE="7"style="width:150px">')
                for d in Decks.all(): #loop thru all available decks
                        self.response.out.write('<OPTION>'+d.name)
                self.response.out.write('</SELECT></div>')
                self.response.out.write('<div style="float:left">')
                #add deck button
                self.response.out.write('<div><button name="clientButton" value="Add deck">----Add Deck to Phone ----&gt;</button></div>')
                #remove deck button
                self.response.out.write('<div><button name="clientButton" value="Remove deck">&lt;- Remove Deck from Phone -</button></div>')
                self.response.out.write('</div>')
                #then the list of decks on the phone
                self.response.out.write('<div style="float:left"><div><label>Decks on client\'s phone:</label></div>'
                            '<SELECT NAME="clientDeck" SIZE="7"style="width:150px">')
                dkAlreadyChosen=c.nowLoaded+c.toLoad #already loaded or to be loaded
                dkAlreadyChosen=[item for item in dkAlreadyChosen if not item in c.toUnload]      #remove those to be unloaded
                for dk in dkAlreadyChosen: #loop thru decks on client phone
                        d=Decks.get(dk)
                        self.response.out.write('<OPTION>'+d.name)
                self.response.out.write('</SELECT></div>')
                self.response.out.write('</div>') #end of deck management
                self.response.out.write('<div style="clear:both;padding-top:1cm">')
                #create new deck button
                self.response.out.write('<button name="clientButton" value="Create New Deck">Create New Deck</button>')     
                #done button
                self.response.out.write('<button name="clientButton" value="Done">Done</button>')
                self.response.out.write('</div>')
                
                self.response.out.write('</form></body></html>')
        def post(self):
                clientID=self.request.query_string
                logging.info("client from post:"+clientID)
                c=Clients.all().filter("cid =",clientID)[0]
                if self.request.get("clientButton")=="Done":
                        self.redirect("/ther")
                elif self.request.get("clientButton")=="Create New Deck":
                        self.redirect("/deckbuilder")
                elif self.request.get("clientButton")=="Add deck":
                        #add deck to phone
                        deckName=self.request.get("availDeck")
                        ##handle case where nothing selected..........................!!!!!
                        dk=Decks.all().filter("name =",deckName)[0].key()
                        if dk in c.nowLoaded:
                                if dk in c.toUnload:
                                        c.toUnload.remove(dk)
                                c.put()
                        else:
                                if not dk in c.toLoad:
                                        c.toLoad.append(dk)
                                if dk in c.toUnload:
                                        c.toUnload.remove(dk)
                                c.put()
                        
                        self.redirect('/client?'+clientID)
                elif self.request.get("clientButton")=="Remove deck":
                        #remove deck from phone
                        deckName=self.request.get("clientDeck")
                        ##handle case where nothing selected..........................!!!!!
                        dk=Decks.all().filter("name =",deckName)[0].key()
                        if dk in c.toLoad:
                                c.toLoad.remove(dk)
                        c.toUnload.append(dk)
                        c.put()
                        self.redirect('/client?'+clientID)
#code from deckbuilder.......................................................................                
class DeckBuilder(webapp.RequestHandler):
        def get(self):
                 self.response.out.write('<html><head><title>Banga Deck Builder</title></head><body>'
				'<center><h1>Banga Deck Builder</h1>'
				'<form action="/deckbuilder" enctype="multipart/form-data" method="post"'
				'<div><label>Deck Name: </label>'
				'<input type="text" name="deck" size="20" maxlength="20"/></div>'
				'<br><input type="submit" value="Create A Deck"/>'
				'</center></form>'
				'</body></html>')

	def post(self):
		dt = DeckTemp()
		dt.name = self.request.get("deck")
		dt.put()
		self.redirect('/newcard?' +dt.name)

class NewCard(webapp.RequestHandler):
  def get(self):
    deckname = self.request.query_string
    dt = DeckTemp.all().filter("name =", deckname)[0]
    self.response.out.write('<html><head><title>Banga Deck Builder - New Card</title></head><body>'
				'<center><h1>Creating a Banga Deck</h1>'
				'</center>'
				'<br>'
				'<h3>New Card</h3>'
				'<form action="/newcard?'+deckname+'" enctype="multipart/form-data" method="post">'
				'<div><label>Card Name: </label>'
                        '<input type="text" name="card" size="20" maxlength="20"/></div>'

				'<div><label>Image: </label>'
				'<input type="file" name="pic" /><div>'
				
				'<div><label>Text Hint: </label>'	
				'<input type="text" name="text1" size="20" maxlength="20"/></div>'
			
				'<div><label>Audio Hint: </label>'
				'<input type="file" name="audio1" /><div>'				
				
				'<div><label>Text Hint: </label>'
				'<input type="text" name="text2" size="20" maxlength="20"/></div>'

				'<div><label>Audio Hint: </label>'
				'<input type="file" name="audio2" /><div>'

				'<div><label>Text Hint: </label>'
				'<input type="text" name="text3" size="20" maxlength="20"/></div>'

				'<div><label>Audio Hint: </label>'
				'<input type="file" name="audio3" /><div>'
				'<div><input type="submit" name="done" value="Add Card to Deck"/></div>'
				'<div><input type="submit" name="done2" value="Finish and View Deck"/></div>'
				'</form></body></html>')
    
       
    
     
				
  def post(self):
    logging.info("in this post");
    deckname = self.request.query_string
    dt = DeckTemp.all().filter("name =", deckname)[0]
    b = self.request.get("done")
    a = self.request.get("done2")
    logging.info("done is "+b)
    logging.info("done2 is "+a)
    
    c = CardTemp()
    c.cardName = self.request.get("card")
    #image = self.request.str_POST['image']
    c.cardImage = db.Blob(self.request.get("pic"))
    #c.cardImage = db.Blob(self.request.str_POST["pic"])
    c.hint1Text = self.request.get("text1")
    c.hint2Text = self.request.get("text2")
    c.hint3Text = self.request.get("text3")
    ar = self.request.get("audio1")
    logging.info("audio1: <"+ar+">")
    if ar == "":
       c.hint1HasAudio = False
    else:
       c.hint1HasAudio = True
       c.hint1Audio = db.Blob(ar)
    ar = self.request.get("audio2")
    logging.info("audio2: <"+ar+">")
    if ar == "":
       c.hint2HasAudio = False
    else:
       c.hint2HasAudio = True
       c.hint2Audio = db.Blob(ar)

    ar = self.request.get("audio3")
    logging.info("audio3: <"+ar+">")
    if ar == "":
       c.hint3HasAudio = False
    else:
       c.hint3HasAudio = True
       c.hint3Audio = db.Blob(ar)

    c.put()
    dt.cards.append(c.key())
    dt.put()
          
          
    if a:
       self.redirect('/info?'+deckname)
    else:
       self.redirect('/newcard?'+deckname)

class CardInfo(webapp.RequestHandler):
  def get(self):
    deckname = self.request.query_string
    dt = DeckTemp.all().filter("name =", deckname)[0]#get deck name from query-string.. get the deck
    for ck in dt.cards:
	c = CardTemp.get(ck)
        self.response.out.write('<html><body>'
				'<center><h3><div>Deck Name: ')
        self.response.out.write(deckname)
        self.response.out.write('</div><div>Card Name: ')
        self.response.out.write(c.cardName)
        self.response.out.write('</div><div>Text Hint: ')
        self.response.out.write(c.hint1Text)
        self.response.out.write('</div><div>Text Hint: ') 
        self.response.out.write(c.hint2Text)
        self.response.out.write('</div><div>Text Hint: ')     
        self.response.out.write(c.hint3Text)
        self.response.out.write('</div></h3><div><img src="/image?'+c.cardName+'" height="300" width="450"></div></center>')
				
    self.response.out.write('<form method="post">'
				'<div><center><input type="submit" value="Accept"></center></div>'
				'</body></html>')

  def post(self):
    deckname = self.request.query_string
    dt = DeckTemp.all().filter("name =", deckname)[0]
    manifest="Deck name: "+deckname
    for ck in dt.cards:
	c = CardTemp.get(ck)
	manifest+="*"+c.cardName
    logging.info("manifest: "+manifest)
    #put deck in db
    d = Decks()
    d.name = deckname
    d.manifest = manifest
    d.put()
    self.redirect("/ther")

class Zip(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'application/octet-stream'
    self.response.out.write(zfile.getvalue())

class Image(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'image/jpg'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		self.response.out.write(ct.cardImage)
class Hint1(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'text/plain'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		self.response.out.write(ct.hint1Text)
           
class Hint2(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'text/plain'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		self.response.out.write(ct.hint2Text)
           
class Hint3(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'text/plain'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		self.response.out.write(ct.hint3Text)

#audio hint classes
#db stuff is:
#hint1Audio=db.BlobProperty()
#hint1HasAudio=db.BooleanProperty()
class Hint1HasAudio(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'text/plain'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		if (ct.hint1HasAudio):
                        response="true"
                else:
                        response="false"
		self.response.out.write(response)
class Hint2HasAudio(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'text/plain'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		if (ct.hint2HasAudio):
                        response="true"
                else:
                        response="false"
		self.response.out.write(response)
class Hint3HasAudio(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'text/plain'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		if (ct.hint3HasAudio):
                        response="true"
                else:
                        response="false"
		self.response.out.write(response)
class Hint1Audio(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'audio/wav'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		self.response.out.write(ct.hint1Audio)
class Hint2Audio(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'audio/wav'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		self.response.out.write(ct.hint2Audio)
class Hint3Audio(webapp.RequestHandler):
	def get(self):
		cardname = self.request.query_string
		self.response.headers['Content-Type'] = 'audio/wav'
		ct = CardTemp.all().filter("cardName =",cardname)[0]
		self.response.out.write(ct.hint3Audio)
           
class Manifest(webapp.RequestHandler):
	def get(self):
		deckname = self.request.query_string
		self.response.headers['Content-Type'] = 'text/plain'
		d = Decks.all().filter("name =",deckname)[0]
		self.response.out.write(d.manifest)
#end deck builder code.......................................................

class Dm0(webapp.RequestHandler):     #request deck mgment command string
        def get(self):
                clientid=self.request.query_string
                c=Clients.all().filter("cid =",clientid)[0]
                command="command "
                for dk in c.toLoad:
                        command+="*load#"+Decks.get(dk).name
                for dk in c.toUnload:
                        command+="*unload#"+Decks.get(dk).name
                logging.info("command: "+command)
                newcontents=c.nowLoaded+c.toLoad
                c.nowLoaded=[item for item in newcontents if not item in c.toUnload]
                c.toLoad=[]
                c.toUnload=[]
                c.put()
		self.response.out.write(command)
class Dm1(webapp.RequestHandler):     #request a deck
        def get(self):
                deckname=self.request.query_string
                logging.info("deckname requested: "+deckname)
                d=Decks.all().filter("name =",deckname)[0]
                self.response.headers['Content-Type'] = 'application/octet-stream'
                self.response.headers['Content-Disposition']='inline;filename="'+deckname+'.deck'
                self.response.out.write(d.zipf)                
"""               
class DeckBuilder(webapp.RequestHandler):
        def get(self):
                self.response.out.write("stub for deck builder utility")
"""
#json processing code
def pyify(json): #convert raw JSON to Python list
    d1=json.replace("{","[")
    d2=d1.replace("}","]")
    d3=d2.replace(":",",")
    return eval(d3)

def names(pjson): #return list of selectors list representing JSON obj
        names=[]
        for i in range(0,len(pjson),2):
            names.append(pjson[i])
        return names

def extractValue(pjson,name): #return list representing value for name in JSON obj
        for i in range(len(pjson)):
            if pjson[i]==name:
                return pjson[i+1]
"""
def convertDate(dateString):
    month,day,year=dateString.split("/")
    return datetime.date(int(year),int(month),int(day)) 
"""
class Report(webapp.RequestHandler):
	def post(self):
		rawReport= self.request.get("report") # get the report from the POST response
		logging.info("rawReport: "+rawReport)
		report=pyify(rawReport)
		clientID=extractValue(report,"client")
		c=Clients.all().filter("cid =",clientID)[0]
		#should handle the case of invalid clientID
		reports=extractValue(report,"stats")
		for r in reports:
                                #create a new StatReports
                                sr=StatReports()
                                sr.deckName=extractValue(r,"deck name")
                                sr.numberRight=int(extractValue(r,"number right"))
                                sr.numberWrong=int(extractValue(r,"number wrong"))
                                #sr.date= convertDate(extractValue(r,"date played"))##need a helper fn that will convert our string to a legal date
				sr.date= extractValue(r, "date played")
                                sr.put()
                                c.stats.append(sr.key())
                                c.put() 



def main():
  logging.getLogger().setLevel(logging.DEBUG)
  application = webapp.WSGIApplication(
                                       [('/', LoginPage),
                                        ('/ther',TherapistPage),
                                        ('/addc',AddClient),
                                        ('/client',ClientPage),
                                        ('/deckbuilder',DeckBuilder),
                                        ('/dm0',Dm0),
                                        ('/dm1',Dm1),
					('/newcard', NewCard),
					('/info', CardInfo),
					('/zip', Zip),
					('/image', Image),
					('/hint1', Hint1),
					('/hint2', Hint2),
					('/hint3', Hint3),
                                        ('/hint1Audio', Hint1Audio),
					('/hint2Audio', Hint2Audio),
					('/hint3Audio', Hint3Audio),
                                        ('/hint1HasAudio', Hint1HasAudio),
					('/hint2HasAudio', Hint2HasAudio),
					('/hint3HasAudio', Hint3HasAudio),
					('/manifest', Manifest),
					('/report', Report)
                                        ],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)
if __name__=="__main__":
  main()
